package com.gregoiresage.pebble4gopro;

import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Semaphore;

import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ImageView;

import com.gregoiresage.pebble4gopro.GoPro.GoProPowerStatus;
import com.gregoiresage.pebble4gopro.Pebble.CommandReceiver;

public class MainActivity extends Activity implements CommandReceiver {

	private GoPro 		gopro;
	private Pebble 		pebble;

	private Thread 		commandThread;
	private boolean 	commandThreadRunning = true;
	private Timer 		timerStatusUpdate;
	private Semaphore 	sema;

	private LinkedList<GoProCommand> commands = new LinkedList<GoProCommand>();
	
	protected void startBackgroundOperation() {
		sema = new Semaphore(0);
		
		// create a timer to schedule a gopro status update each second
		timerStatusUpdate = new Timer();
		timerStatusUpdate.schedule(new TimerTask() {
			@Override
			public void run() {
				sema.release();
			}
		},1000, 1000);

		// Fire off a thread to do some work that we shouldn't do directly in the UI thread
		commandThread = new Thread() {
			public void run() {
				commandThreadRunning = true;
				while(commandThreadRunning){
					try {
						// block until a new command arrives or a gopro status update is required
						sema.acquire();
					} catch (InterruptedException e) {
						Log.e("GOPRO", e.getMessage(), e);
					}
					
					
					// Update UI
					final boolean pebbleConnected = pebble.isConnected();
					final GoProPowerStatus powerStatus = gopro.getPowerStatus();
					runOnUiThread(new Runnable() {
						@Override
						public void run() {
							ImageView image = (ImageView) findViewById(R.id.imagePebble);
							image.setBackgroundResource(pebbleConnected ? R.drawable.backon : R.drawable.backoff);					
							image = (ImageView) findViewById(R.id.imageGopro);
							if(powerStatus == GoProPowerStatus.ON){
								image.setBackgroundResource(R.drawable.backon);
							}
							else if(powerStatus == GoProPowerStatus.IDLE){
								image.setBackgroundResource(R.drawable.backidle);
							}
							else {
								image.setBackgroundResource(R.drawable.backoff);
							}
						}
					});
					
					if(commandThreadRunning && pebble.isConnected()){
						if(gopro.getPowerStatus() != GoProPowerStatus.ON){
							gopro.connect();
						}
						
						byte[] gopro_data = null;
						
						if(gopro.getPowerStatus() != GoProPowerStatus.OFF){
							// manage all the commands in the list
							boolean commandIsEmpty = false;
							synchronized (commands) {
								commandIsEmpty = commands.isEmpty();
							}
							while(!commandIsEmpty){
								GoProCommand command = null;
								synchronized (commands) {
									command = commands.pop();
									commandIsEmpty = commands.isEmpty();
								}
								// send a command to the gopro
								gopro.sendCommand(command);
							}
							
							// retrieve the status of the gopro
							gopro_data = gopro.getStatus();
							
							// send the gopro status if the gopro is on
							if(gopro.getPowerStatus() == GoProPowerStatus.ON){
								pebble.sendStatus(getApplicationContext(), gopro_data);
							}
						}
						else {
							// clear the list of commands if any
							synchronized (commands) {
								commands.clear();
							}
						}
						
						// send the new power status
						pebble.sendPowerStatus(getApplicationContext(), gopro.getPowerStatus().value);
					}
				}		
			}
		};
		commandThread.start();
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
	    MenuInflater inflater = getMenuInflater();
	    inflater.inflate(R.menu.menu, menu);
	    return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
	    // Handle item selection
	    switch (item.getItemId()) {
	        case R.id.item1:
	            pebble.installWatchApp(this);
	            return true;
	        default:
	            return super.onOptionsItemSelected(item);
	    }
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		setContentView(R.layout.activity_main);

		if (android.os.Build.VERSION.SDK_INT > 9) {
			StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
			StrictMode.setThreadPolicy(policy);
		}
				
		gopro 	= new GoPro();
		pebble 	= new Pebble();

		pebble.register(getApplicationContext());
		pebble.registerCommandReceiver(this);
		pebble.startGoProWatchApp(getApplicationContext());
		
		startBackgroundOperation();
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		pebble.startGoProWatchApp(getApplicationContext());
	}
	
	@Override
	protected void onDestroy() {
		pebble.unregister(getApplicationContext());
		pebble.stopGoProWatchApp(getApplicationContext());
		
		commandThreadRunning = false;
		timerStatusUpdate.cancel();
		sema.release();
		
		try {
			commandThread.join();
		} catch (InterruptedException e) {
			Log.e("GOPRO", e.getMessage(), e);
		}
				
		super.onDestroy();
	}

	@Override
	public void receiveCommand(GoProCommand command) {
		synchronized (commands) {
			commands.addLast(command);
			// notify the background thread a new command has arrived
			sema.release();
		}
	}
	
	
}
